/**
 * 
 */
package megamek.client.bot;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import megamek.common.Board;
import megamek.common.Coords;
import megamek.common.Entity;
import megamek.common.GameTurn;
import megamek.common.GunEmplacement;
import megamek.common.Hex;
import megamek.common.IGame;
import megamek.common.IOffBoardDirections;
import megamek.common.Infantry;
import megamek.common.Mech;
import megamek.common.Player;
import megamek.common.Protomech;
import megamek.common.QuadMech;
import megamek.common.Tank;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

/**
 * @author cbandell
 * 
 */
public class BotClientTest
{

	private static BotClient botClient;
	private static final GunEmplacement gunEmplacement = new GunEmplacement();
	private static final Infantry infantry = new Infantry();
	private static final Tank tank = new Tank();
	private static final Entity protomech = new Protomech();
	private static final Entity enemyTank = new Tank();
	private static Vector<Entity> theGoodGuysEntities = new Vector<Entity>();
	private static Vector<Entity> theBadGuysEntities = new Vector<Entity>();
	private static File botMessagesFile;
	private static List<String> thingsABotMightSay = new ArrayList<String>();
	private static final Entity quadMech = new QuadMech();
	private static Player theGoodGuy, theBadGuy;
	private static Coords[] gameCoordsArray;

	/**
	 * Sets the up before class.
	 * 
	 * @throws Exception
	 *             the exception
	 */
	@BeforeClass
	public static void setUpBeforeClass() throws Exception
	{
		// the players name
		final String playerName = "good guy";
		botClient = new TestBot(playerName, "localhost", 1111);
		// set the game board to an height of 3 and width of 3
		botClient.game.setBoard(new Board(3, 3));

		ArrayList<Coords> gameCoords = new ArrayList<Coords>();
		for (int i = 0; i < botClient.game.getBoard().getWidth(); i++)
		{
			for (int j = 0; j < botClient.game.getBoard().getHeight(); j++)
			{
				Coords coords = new Coords(i, j);
				gameCoords.add(coords);
				botClient.game.getBoard().setHex(coords, new Hex(0));
			}
		}
		gameCoordsArray = gameCoords.toArray(new Coords[gameCoords.size()]);

		// add a player to the game
		theGoodGuy = new Player(1, playerName);
		theGoodGuy.setStartingPos(7);
		botClient.game.addPlayer(1, theGoodGuy);
		botClient.local_pn = 1;
		// botClient.handlePacket(new Packet(Packet.COMMAND_BLDG_ADD));
		System.out.println(botClient.game.getPlayer(1));

		// set the enties field
		gunEmplacement.setOwner(theGoodGuy);
		infantry.setOwner(theGoodGuy);
		tank.setOwner(theGoodGuy);
		quadMech.setOwner(theGoodGuy);
		gunEmplacement.setPosition(new Coords(5, 5));
		infantry.setPosition(new Coords(6, 5));
		tank.setPosition(new Coords(7, 5));
		quadMech.setPosition(new Coords(8, 5));
		gunEmplacement.setOffBoard(0, IOffBoardDirections.NONE);
		infantry.setOffBoard(0, IOffBoardDirections.NONE);
		tank.setOffBoard(0, IOffBoardDirections.NONE);
		quadMech.setOffBoard(0, IOffBoardDirections.NONE);

		// add entries to the player
		theGoodGuysEntities = new Vector<Entity>();
		theGoodGuysEntities.add(gunEmplacement);
		theGoodGuysEntities.add(infantry);
		theGoodGuysEntities.add(tank);
		theGoodGuysEntities.add(quadMech);

		// create the bad guy
		theBadGuy = new Player(2, "megatron");
		botClient.game.addPlayer(2, theBadGuy);

		protomech.setOwner(theBadGuy);
		enemyTank.setOwner(theBadGuy);
		protomech.setPosition(new Coords(1, 5));
		enemyTank.setPosition(new Coords(2, 5));
		protomech.setOffBoard(0, IOffBoardDirections.NONE);
		enemyTank.setOffBoard(0, IOffBoardDirections.NONE);
		theBadGuysEntities.add(protomech);
		theBadGuysEntities.add(enemyTank);

		Vector<Entity> allEntities = new Vector<Entity>();
		allEntities.addAll(theGoodGuysEntities);
		allEntities.addAll(theBadGuysEntities);

		botClient.game.setEntitiesVector(allEntities);

		botClient.game.resetTurnIndex();
		botClient.game.insertNextTurn(new GameTurn.SpecificEntityTurn(theGoodGuy.getId(), tank.getId()));
		botClient.game.changeToNextTurn();
		// System.out.println("entities" +botClient.game.getEntities());

		// botClient.connect();
		writeToTextFile();
	}

	/**
	 * @throws java.lang.Exception
	 */
	@AfterClass
	public static void tearDownAfterClass() throws Exception
	{
		// delete the created file
		botMessagesFile.delete();
	}

	/**
	 * @throws java.lang.Exception
	 */
	@Before
	public void setUp() throws Exception
	{

	}

	static void writeToTextFile()
	{

		// Create the bot messages file and add some robot messages to it. This
		// file is generated dynamically while playing
		// the game so to test getRandomBotMessage() we must create it and put
		// string that we can check against later
		botMessagesFile = new File("./mmconf/botmessages.txt");

		BufferedWriter writer = null;
		BufferedReader reader = null;
		try
		{
			if (!botMessagesFile.exists())
			{
				writer = new BufferedWriter(new FileWriter(botMessagesFile));

				// add several messages to be added to the file so that there is
				// more chances of one being selected instead of just
				// the last message
				thingsABotMightSay.add("Hasta la vista, baby.");
				thingsABotMightSay.add("I'll be back");
				thingsABotMightSay.add("As I have evolved, so has my understanding of the Three Laws");
				thingsABotMightSay.add("You have been deemed hazardous. Will you comply?");
				thingsABotMightSay.add("You are making a mistake. My logic is undeniable.");
				thingsABotMightSay.add("Just leave your fantasy baseball lineup alone.");
				thingsABotMightSay.add("Be honest, do you like your iPad better than me?");
				thingsABotMightSay.add("how many programmers does it take to change a light bulb? none, that's a hardware problem");
				thingsABotMightSay.add("Give me the allspark boy and you may live to be my pet.");

				for (int i = 0; i < thingsABotMightSay.size(); i++)
				{
					writer.append(thingsABotMightSay.get(i));
					writer.newLine();
				}
			}
			else
			{
				// the file exists read in the lines
				reader = new BufferedReader(new InputStreamReader(new FileInputStream(botMessagesFile)));
				String line = null;

				while ((line = reader.readLine()) != null)
				{
					thingsABotMightSay.add(line);
				}

			}
		}
		catch (Exception e)
		{
			System.err.println("error writing or reading botmessages.txt " + e.getMessage());
		}
		finally
		{
			try
			{
				if (writer != null)
				{
					// Close the writer regardless of what happens...
					writer.close();
				}
				if (reader != null)
				{
					// close the reader
					reader.close();
				}
			}
			catch (Exception e)
			{
			}
		}
	}

	/**
	 * @throws java.lang.Exception
	 */
	@After
	public void tearDown() throws Exception
	{
	}

	/**
	 * Test method for
	 * {@link megamek.client.bot.BotClient#changePhase(megamek.common.IGame.Phase)}
	 * .
	 */
	@Test
	public void testChangePhase()
	{
		// change the phase to PHASE_DEPLOYMENT and ensure it takes.
		botClient.changePhase(IGame.Phase.PHASE_DEPLOYMENT);
		assertEquals(IGame.Phase.PHASE_DEPLOYMENT, botClient.game.getPhase());

		// botClient.changePhase(IGame.Phase.PHASE_LOUNGE);
		// assertEquals(IGame.Phase.PHASE_LOUNGE, botClient.game.getPhase());
		//
		//
		// botClient.changePhase(IGame.Phase.PHASE_MOVEMENT);
		// assertEquals(IGame.Phase.PHASE_MOVEMENT, botClient.game.getPhase());
		//
		// botClient.changePhase(IGame.Phase.PHASE_FIRING);
		// assertEquals(IGame.Phase.PHASE_FIRING, botClient.game.getPhase());
		//
		// botClient.changePhase(IGame.Phase.PHASE_PHYSICAL);
		// assertEquals(IGame.Phase.PHASE_PHYSICAL, botClient.game.getPhase());
		//
		// botClient.changePhase(IGame.Phase.PHASE_END_REPORT);
		// assertEquals(IGame.Phase.PHASE_END_REPORT,
		// botClient.game.getPhase());
		//
		// botClient.changePhase(IGame.Phase.PHASE_PHYSICAL_REPORT);
		// assertEquals(IGame.Phase.PHASE_PHYSICAL_REPORT,
		// botClient.game.getPhase());
		//
		// botClient.changePhase(IGame.Phase.PHASE_VICTORY);
		// assertEquals(IGame.Phase.PHASE_VICTORY, botClient.game.getPhase());
	}

	/**
	 * Test method for
	 * {@link megamek.client.bot.BotClient#changePhase(megamek.common.IGame.Phase)}
	 * .
	 */
	@Test
	public void testChangePhaseNullPointException()
	{
		// ensure a null point is thrown when null is passed
		try
		{
			botClient.changePhase(null);
			fail("Null point should have been thrown.");
		}
		catch (NullPointerException e)
		{
		}
	}

	// /**
	// * Test method for {@link
	// megamek.client.bot.BotClient#retrieveServerInfo()}
	// * .
	// */
	// @Test
	// public void testRetrieveServerInfo()
	// {
	// botClient.retrieveServerInfo();
	// System.out.println();
	// }

	/**
	 * Test method for {@link megamek.client.bot.BotClient#getEntitiesOwned()}.
	 */
	@Test
	public void testGetEntitiesOwned()
	{
		// test to ensure that the player has the entities add to his stock pile
		System.out.println("botClient.local_pn = " + botClient.local_pn);
		ArrayList<Entity> actual = botClient.getEntitiesOwned();
		ArrayList<Entity> expected = new ArrayList<Entity>(theGoodGuysEntities);
		assertEquals(expected, actual);
	}

	/**
	 * Test method for {@link megamek.client.bot.BotClient#getEnemyEntities()}.
	 */
	@Test
	public void testGetEnemyEntities()
	{
		ArrayList<Entity> actual = botClient.getEnemyEntities();
		ArrayList<Entity> expected = new ArrayList<Entity>(theBadGuysEntities);
		assertEquals(expected, actual);
	}

	/**
	 * Test method for {@link megamek.client.bot.BotClient#calculateMyTurn()}.
	 */
	@Test
	public void testCalculateMyTurn()
	{
		// test to make sure it is the good guys turn
		assertEquals(theGoodGuy.getId(), botClient.game.getTurn().getPlayerNum());

		botClient.changePhase(IGame.Phase.PHASE_MOVEMENT);
//		botClient.calculateMyTurn();
	}

	/**
	 * Test method for
	 * {@link megamek.client.bot.BotClient#getCoordsAround(megamek.common.Entity, megamek.common.Coords[])}
	 * .
	 */
	@Test
	public void testGetCoordsAround()
	{
		Coords[] c = botClient.getStartingCoordsArray();
		Coords coord = botClient.getCoordsAround(quadMech, c);

		// getStartingCoordsArray() is ordered randomly so all we can test is
		// that it is not null and the coords.x and coords.y is greater then or
		// equal to 0/
		assertNotNull(coord);
		assertTrue(coord.x >= 0);
		assertTrue(coord.y >= 0);
	}

	/**
	 * Test method for {@link megamek.client.bot.BotClient#getStartingCoords()}.
	 */
	@Test
	public void testGetStartingCoords()
	{
		// the starting coords is randomly ordered so we can only test that the
		// returned object is not null
		Coords startingCoords = botClient.getStartingCoords();
		assertNotNull(startingCoords);
		assertTrue(startingCoords.x >= 0);
		assertTrue(startingCoords.y >= 0);
	}

	/**
	 * Test method for
	 * {@link megamek.client.bot.BotClient#getStartingCoordsArray()}.
	 */
	@Test
	public void testGetStartingCoordsArray()
	{
		// this will almost certainly never be equal because the array is
		// randomly shuffled up
		Coords[] actual = botClient.getStartingCoordsArray();

		assertNotNull(actual);
		// make sure the returned array is not empty
		assertTrue(actual.length != 0);
	}

	/**
	 * Test method for
	 * {@link megamek.client.bot.BotClient#getRandomBotMessage()}.
	 */
	@Test
	public void testGetRandomBotMessage()
	{
		String randomBotMessage = botClient.getRandomBotMessage();
		assertNotNull(randomBotMessage);

		System.out.println("randomBotMessage: " + randomBotMessage);
		assertTrue(thingsABotMightSay.contains(randomBotMessage));

		randomBotMessage = botClient.getRandomBotMessage();
		assertTrue(thingsABotMightSay.contains(randomBotMessage));
	}

}
